package dao

import (
	"context"
	"github.com/pkg/errors"
	"gorm.io/gorm"
	"gorm.io/gorm/clause"
	"pay/api/pay"
	"pay/internal/model"
	"time"
)

func (d *Dao) FindAlipayValidConfigsByPage(ctx context.Context, sgId, pStoreId, pageNo, pageSize uint32) (
	configs []*model.AlipayConfigQueryModel, total int64, err error) {
	db := d.TransContext(ctx).Model(&model.AlipayConfig{}).Joins(
		"JOIN pay_alipay_token ON token_id=pay_alipay_config.id").Select(
		"pay_alipay_config.*, app_id, app_id, user_id, account_status").Where(
		"sg_id = ? AND p_store_id = ? AND pay_alipay_config.status = ? "+
			"AND pay_alipay_token.status = ? AND pay_alipay_token.account_status in ?",
		sgId, pStoreId, true, true, []int{int(pay.AlipayAccountStatus_valid),
			int(pay.AlipayAccountStatus_restrictValid)})
	if err = db.Count(&total).Error; err != nil {
		err = d.processSqlError(err)
		return
	}
	if err = db.Limit(int(pageSize)).Offset(int((pageNo - 1) * pageSize)).Scan(&configs).Error; err != nil {
		err = d.processSqlError(err)
		return
	}
	return
}

func (d *Dao) FindAlipayConfigsByPage(ctx context.Context, sgId, pStoreId, pageNo, pageSize uint32) (
	configs []*model.AlipayConfigQueryModel, total int64, err error) {
	db := d.TransContext(ctx).Model(&model.AlipayConfig{}).Joins(
		"JOIN pay_alipay_token ON token_id=pay_alipay_token.id").Select(
		"pay_alipay_config.*, app_id, app_id, user_id, account_status").Where(
		"sg_id = ? AND p_store_id = ? AND pay_alipay_config.status = ? AND pay_alipay_token.status = ?",
		sgId, pStoreId, true, true)
	if err = db.Count(&total).Error; err != nil {
		err = d.processSqlError(err)
		return
	}
	if err = db.Limit(int(pageSize)).Offset(int((pageNo - 1) * pageSize)).Scan(&configs).Error; err != nil {
		err = d.processSqlError(err)
		return
	}
	return
}

func (d *Dao) FindAlipayConfigsByIds(ctx context.Context, ids []uint32, sgId uint32) (
	configs []*model.AlipayConfigQueryModel, err error) {
	if err = d.TransContext(ctx).Model(&model.AlipayConfig{}).Joins(
		"JOIN pay_alipay_token ON token_id=pay_alipay_config.id").Select(
		"pay_alipay_config.*, app_id, user_id, account_status").Where(
		"pay_alipay_config.id in ? AND sg_id = ? "+
			"AND pay_alipay_config.status = ? AND pay_alipay_token.status = ?",
		ids, sgId, true, true).Scan(&configs).Error; err != nil {
		err = d.processSqlError(err)
		return
	}
	return
}

func (d *Dao) GetAlipayConfig(ctx context.Context, configId, sgId, pStoreId uint32) (
	config *model.AlipayConfig, err error) {
	config = &model.AlipayConfig{}
	if err = d.TransContext(ctx).Model(&model.AlipayConfig{}).Where(
		"id = ? AND sg_id = ? AND p_store_id = ? AND status = ?",
		configId, sgId, pStoreId, true).Take(config).Error; err != nil {
		err = d.processSqlError(err)
		return
	}
	return
}

func (d *Dao) GetAlipayConfigById(ctx context.Context, configId, sgId uint32) (
	config *model.AlipayConfig, err error) {
	config = &model.AlipayConfig{}
	if err = d.TransContext(ctx).Model(&model.AlipayConfig{}).Where(
		"id = ? AND sg_id = ? AND status = ?",
		configId, sgId, true).Take(config).Error; err != nil {
		err = d.processSqlError(err)
		return
	}
	return
}

func (d *Dao) FindAlipayConfigByAuthorize(ctx context.Context, tokenId, sgId, pStoreId uint32) (
	configs []*model.AlipayConfig, err error) {
	err = d.processSqlError(d.TransContext(ctx).Model(&model.AlipayConfig{}).Where(
		"sg_id = ? AND p_store_id = ? AND token_id = ? AND status = ?",
		sgId, pStoreId, tokenId, true).Scan(&configs).Error)
	return
}

// Lock 锁定单条记录
func (d *Dao) LockAlipayTokenByID(ctx context.Context, rcv interface{}, id interface{}) error {
	return d.processSqlError(d.TransContext(ctx).Clauses(
		clause.Locking{Strength: "UPDATE"}).Where(
		"id = ? AND status = ?",
		id, true).Take(rcv).Error)
}

// Lock 锁定单条记录
func (d *Dao) LockAlipayTokenByAppID(ctx context.Context, rcv interface{}, appId string) error {
	return d.processSqlError(d.TransContext(ctx).Clauses(
		clause.Locking{Strength: "UPDATE"}).Where(
		"app_id = ?", appId).Take(rcv).Error)
}

func (d *Dao) GetAlipayTokenByID(ctx context.Context, tokenId uint32) (token *model.AlipayToken, err error) {
	token = &model.AlipayToken{}
	err = d.processSqlError(d.TransContext(ctx).Where(
		"id = ? AND status = ?", tokenId, true).Take(&token).Error)
	return
}

func (d *Dao) CanAlipayTokenDisabled(ctx context.Context, tokenId uint32) bool {
	config := &model.AlipayConfig{}
	if err := d.TransContext(ctx).Model(&model.AlipayConfig{}).Where(
		"token_id = ? AND status = ?",
		tokenId, true).Take(config).Error; err != nil {
		err = d.processSqlError(err)
		if errors.Cause(err) == gorm.ErrRecordNotFound {
			return true
		}
	}
	return false
}

func (d *Dao) DisableAlipayToken(ctx context.Context, tokenId uint32) (err error) {
	if err = d.TransContext(ctx).Model(&model.AlipayConfig{ID: tokenId}).Updates(
		map[string]interface{}{
			"status": false,
		}).Error; err != nil {
		err = d.processSqlError(err)
		return
	}
	return
}

func (d *Dao) FindAlipayExpiringTokens(ctx context.Context) (
	tokens []*model.AlipayToken, err error) {
	err = d.processSqlError(d.TransContext(ctx).Model(&model.AlipayToken{}).Where(
		"expire_time <= ?",
		time.Now().Add(-time.Hour*24*3)).Scan(&tokens).Error)
	return
}
